<template>
  <div id="picker-container">
    <div class="picker-header">
      <div class="pointer month" @click="lastYear">上一年</div>
      <div class="pointer month" @click="lastMonth">上月</div>
      <div class="date">{{ proxy.$utils.dateTimeFormateFn(currentDate,'yearMonth') }}</div>
      <div class="pointer month" @click="nextMonth">下月</div>
      <div class="pointer month" @click="nextYear">下一年</div>
    </div>
    <div class="picker-date">
      <ul class="picker-week">
        <li v-for="(item, index) in weekday" :key="index">{{ item }}</li>
      </ul>
      <div class="calendar-container">
        <ul class="calendar-date" v-for="(item, index) in calendarList" :key="index">
          <li class="day pointer" :class="{ active: selectDate.includes(child.date), disabled: defaultData.includes(child.date) }" :style="{ color: child.textColor }" v-for="(child, i) in item" :key="i" @click="() => selectDay(child)">
            {{ child.day }}
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
 
<script lang="ts" setup name="picker">
const { proxy } = getCurrentInstance();
let props = defineProps(["modelValue", "mode", "defaultData"]);
const emit = defineEmits(["update:modelValue"]);

defineExpose();
const currentDate = ref<string>("");
const selectDate = ref<any[]>(props.data);
const date = reactive<Date>(new Date());
const weekday = ref<string[]>(["一", "二", "三", "四", "五", "六", "日"]);
let defaultData = ref([]); //默认选中

// 去年
function lastYear() {
  yearFormat("lastMonth");
}

// 明年
function nextYear() {
  yearFormat("nextMonth");
}

// 上个月
function lastMonth() {
  monthFormat("lastMonth");
}

// 下个月
function nextMonth() {
  monthFormat("nextMonth");
}

// 第一步：先获取日期，默认获取当前日期
function getDefaultHeaderDate() {
  let setData = currentDate.value ? new Date(currentDate.value) : date;
  //console.log("setData", setData);
  const year = setData.getFullYear();
  const month =
    setData.getMonth() + 1 < 10
      ? `0${setData.getMonth() + 1}`
      : setData.getMonth() + 1;
  const day =
    setData.getDate() < 10 ? `0${setData.getDate()}` : setData.getDate();
  //如果是单选，并且有默认日期
  if (props.mode == "single" && selectDate.value.length) {
    currentDate.value = selectDate.value[0];
  } else {
    currentDate.value = `${year}-${month}-${day}`;
  }
  if (!selectDate.value.length && !props.defaultData)
    selectDate.value = [currentDate.value];
  getCalendar();
}

// 获取天数
function getDays(year: number, month: number) {
  // 每月的天数写在数组中，再判断时闰年还是平年确定2月分的天数
  let days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
    days[1] = 29;
  }
  return days[month];
}

// 获取每个月第一天是星期几
function getWeekDays(year: number, month: number): number {
  var monthFirstWeekDay = new Date(year, month - 1, 1).getDay(); // 返回本月1号是星期几
  return monthFirstWeekDay;
}

// 第二步：获取日期列表
const calendarList = ref<any>([]);
function getCalendar() {
  calendarList.value = [];
  const dateArray = currentDate.value.split("-");
  if (!dateArray.length) return;
  const year = Number(dateArray[0]);
  const month = Number(dateArray[1]); // 减一 ，因为初始化已经加一了
  const daysNumber = getDays(year, month - 1); //

  // 本月全部天数

  for (let i = 1; i <= daysNumber; i++) {
    const day = i < 10 ? `0${i}` : i;
    const item = {
      date: `${dateArray[0]}-${dateArray[1]}-${day}`,
      year: dateArray[0],
      month: dateArray[1],
      day: Number(day),
      textColor: "#000",
    };
    calendarList.value.push(item);
  }

  // 拼接上个月日期数据
  let firstWeekDay = getWeekDays(year, month);
  firstWeekDay = firstWeekDay === 0 ? 6 : firstWeekDay - 1;
  const lastMonth = preLastMonth(firstWeekDay);
  calendarList.value.unshift(...lastMonth);

  // 拼接下个月数据
  const length = calendarList.value.length;
  const nextMonth = preNextMonth(length);
  calendarList.value.push(...nextMonth);
  dateToWeek();
}

// 获取上个月的日期，并返回数据，添加到原本的数据结构中
function preLastMonth(days: number) {
  const dateArray = currentDate.value.split("-");
  let year = Number(dateArray[0]);
  let month: string | number = Number(dateArray[1]);
  month = month - 1 === 0 ? 12 : month - 1; // 同样减去 1 ，才能拿到上一个月
  if (month === 12) {
    year = Number(dateArray[0]) - 1;
  }
  let preDaysNumber = getDays(year, month - 1); // 某月总天数
  month = month < 10 ? `0${month}` : month;

  // 获取上个月的日期，循环几次，就代表从上个月拿多少天
  const lastMonth = [];
  while (lastMonth.length !== days) {
    const day = preDaysNumber < 10 ? `0${preDaysNumber}` : preDaysNumber;
    const item = {
      date: `${year}-${month}-${day}`,
      year,
      month,
      day: Number(day),
      textColor: "#ccc",
      type: "last",
    };
    lastMonth.push(item);
    preDaysNumber--;
  }
  return lastMonth.reverse();
}

// 获取下个月的日期，并返回数据，添加到原本的数据结构中
function preNextMonth(length: number) {
  // 42 为固定数量，可以参考电脑的日历组件一个面板天数
  const diff = 42 - length;

  const dateArray = currentDate.value.split("-");
  let year = Number(dateArray[0]);
  let month: string | number = Number(dateArray[1]);
  month = month === 12 ? 1 : month + 1; // 当前月加上一 等于下一个月
  if (month === 1) {
    year = Number(dateArray[0]) + 1;
  }
  month = month < 10 ? `0${month}` : month;

  // 获取下个月的日期，循环几次，就代表从下个月拿多少天
  const nextMonth = [];
  let numberDays = 1;
  while (nextMonth.length !== diff) {
    const day = numberDays < 10 ? `0${numberDays}` : numberDays;
    const item = {
      date: `${year}-${month}-${day}`,
      year,
      month,
      day: Number(day),
      textColor: "#ccc",
      type: "next",
    };
    nextMonth.push(item);
    numberDays++;
  }
  return nextMonth;
}

// 将天数转换成对应的周的日期
function dateToWeek() {
  calendarList.value;
  const array = [];
  while (array.length !== 6) {
    array.push(calendarList.value.splice(0, 7));
  }
  calendarList.value = array;
}

// 获取默认的日期
function monthFormat(type: string) {
  let dateArray = currentDate.value.split("-");
  let month = dateArray.length ? Number(dateArray[1]) : null;
  if (!month) {
    return new Error("当前月份是 null 啦 ~兄弟");
  }
  let monthData;
  if (type === "lastMonth") {
    monthData = month - 1 === 0 ? 12 : month - 1;
    if (monthData === 12) {
      let beforeYear = Number(dateArray[0]) - 1;
      dateArray.splice(0, 1, beforeYear);
    }
  } else {
    monthData = month === 12 ? 1 : month + 1;
    if (monthData === 1) {
      let nextYear = Number(dateArray[0]) + 1;
      dateArray.splice(0, 1, nextYear);
    }
  }
  let results = monthData < 10 ? `0${monthData}` : monthData;
  dateArray.splice(1, 1, results);
  currentDate.value = dateArray.join("-");
  getCalendar();
}

// 用户调整年份
function yearFormat(type: string) {
  let dateArray = currentDate.value.split("-");
  if (type === "lastMonth") {
    let beforeYear = Number(dateArray[0]) - 1;
    dateArray.splice(0, 1, beforeYear);
  } else {
    let nextYear = Number(dateArray[0]) + 1;
    dateArray.splice(0, 1, nextYear);
  }
  currentDate.value = dateArray.join("-");
  getCalendar();
}

// 用户选中日期
function selectDay(record: { date: string; type: string }) {
  if (record.type === "last") {
    lastMonth();
  } else if (record.type === "next") {
    nextMonth();
  }
  currentDate.value = record.date;
  const index = selectDate.value.findIndex((item) => item == record.date);
  if (index !== -1) {
    selectDate.value.splice(index, 1);
    return;
  }
  if (props.mode === "single") selectDate.value = [toRaw(record.date)];
  else selectDate.value.push(record.date);

  console.log("selectDate.value", selectDate.value);
  if (props.mode == "single") {
    emit("update:modelValue", selectDate.value.toString());
  } else {
    emit("update:modelValue", selectDate.value);
  }
}

watch(
  () => [props.modelValue, props.defaultData],
  (newValue, oldValue) => {
    console.log("newValue-props.modelValue", props.modelValue);
    if (props.modelValue) {
      if (proxy.$utils.isString(props.modelValue)) {
        selectDate.value = [props.modelValue];
      } else {
        selectDate.value = props.modelValue;
      }
    }
    if (!props.modelValue.length) currentDate.value = "";
    if (props.defaultData) {
      defaultData.value = props.defaultData;
    } else {
      defaultData.value = [];
    }
    getDefaultHeaderDate();
  },
  { immediate: true, deep: true }
);
</script>
 
<style lang="scss" scoped>
#picker-container {
  width: 100%;
  .picker-header {
    width: 100%;
    display: flex;
    justify-content: space-around;
    align-items: center;
    border-bottom: 1px solid #ccc;
    padding-bottom: 10px;
    box-sizing: border-box;
    user-select: none;
  }
  .picker-date {
    border: 1px solid #ccc;
    border-top: none;
    width: 100%;
    // height: 300px;
    .picker-week {
      display: flex;
      justify-content: space-around;
      align-items: center;
      list-style: none;
      border-bottom: 1px solid #ccc;
    }
    .calendar-container {
      width: 100%;
      height: 100%;
      .calendar-date {
        height: 50px;
        display: flex;
        justify-content: space-around;
        align-items: center;
        list-style: none;
        user-select: none;
        .day {
          width: 50px;
          height: 50px;
          display: flex;
          align-items: center;
          justify-content: center;
          transition: all 0.3s;
        }
        .active {
          background-color: var(--el-color-primary) !important;
          color: white !important;
          border-radius: 8px;
          width: 40px;
          height: 40px;
        }
        .disabled {
          background-color: #ccc;
          color: white !important;
          border-radius: 8px;
          width: 40px;
          height: 40px;
          //cursor: not-allowed;
        }
      }
    }
  }
}
</style>